package me.android.library.common.service;


import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;

import com.blankj.utilcode.util.AppUtils;
import com.blankj.utilcode.util.TimeUtils;
import com.google.common.collect.Maps;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.util.Map;

import cn.hutool.core.thread.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import me.android.library.utils.android.AppUtil;
import me.android.library.utils.android.FileUtil;
import me.android.library.utils.android.ToastUtil;
import mylab.utils.common.StringUtil;

@Slf4j
public class CrashLogService extends AbstractService {
    private static class SingletonHolder {
        @SuppressLint("StaticFieldLeak")
        static final CrashLogService instance = new CrashLogService();
    }

    public static CrashLogService getInstance() {
        return CrashLogService.SingletonHolder.instance;
    }


    private final UncaughtExceptionHandler mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
    private final Map<String, String> infos = Maps.newConcurrentMap();
    private OnCrashedListener listener;

    private CrashLogService() {
    }

    @Override
    public void init() {
        super.init();
        Thread.setDefaultUncaughtExceptionHandler(errorHandler);
    }

    public void setOnCrashedListener(OnCrashedListener l) {
        listener = l;
    }

    private void handleException(Throwable ex) {
        if (ex == null) {
            return;
        }

        if (AppUtil.isDebug()) {
            ToastUtil.showLong(ex.getMessage());
        }

        // 收集设备参数信息
        collectDeviceInfo(getContext());
        // 保存日志文件
        String log = saveCrashInfo2File(ex);
        onCrashLog(log);
    }

    private void collectDeviceInfo(Context ctx) {
        // 1. 空指针防护：上下文为空直接返回
        if (ctx == null) {
            log.warn("collectDeviceInfo: Context is null, skip collecting");
            return;
        }

        // 2. 收集应用版本信息
        try {
            PackageManager pm = ctx.getPackageManager();
            if (pm == null) {
                log.warn("collectDeviceInfo: PackageManager is null, skip version info");
                return;
            }
            // 仅获取版本信息，无需GET_ACTIVITIES（减少资源消耗）
            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), 0);
            if (pi != null) {
                // 版本名称（处理null情况）
                String versionName = pi.versionName == null ? "null" : pi.versionName;
                infos.put("versionName", versionName);

                // 版本号（兼容API 28+，versionCode已过时）
                long versionCode;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { // API 28+
                    versionCode = pi.getLongVersionCode();
                } else {
                    versionCode = pi.versionCode;
                }
                infos.put("versionCode", String.valueOf(versionCode));
            }
        } catch (PackageManager.NameNotFoundException e) {
            log.warn("collectDeviceInfo: Failed to get PackageInfo", e);
        }

        // 3. 收集设备Build信息（如型号、厂商等）
        Field[] fields = Build.class.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                Object value = field.get(null); // 获取静态字段值（Build类字段均为static）
                // 安全转换为字符串（支持所有类型，避免ClassCastException）
                infos.put(field.getName(), value != null ? value.toString() : "null");
            } catch (IllegalAccessException e) {
                log.warn("collectDeviceInfo: Failed to access field " + field.getName(), e);
            } catch (Exception e) {
                log.warn("collectDeviceInfo: Unknown error for field " + field.getName(), e);
            }
        }
    }

    private String saveCrashInfo2File(Throwable ex) {

        String RN = System.lineSeparator();

        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : infos.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key).append("=").append(value).append(RN);
        }

        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        ex.printStackTrace(printWriter);
        Throwable cause = ex.getCause();
        while (cause != null) {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }
        printWriter.close();
        String result = writer.toString();
        sb.append(result);

        try {
            // Get Downloads directory path
            String appName = AppUtils.getAppName();
            String time = TimeUtils.getNowString();
            String fileName = StringUtil.format("{}-crash-{}.txt", appName, time);
            String fileContent = sb.toString();

            FileUtil.writeToDownload(getContext(), fileContent, fileName);
        } catch (Exception e) {
            log.warn("write crashLog error", e);
        }

        return sb.toString();
    }

    private void onCrashLog(String log) {
        if (listener != null) {
            listener.onCrashed(log);
        }
    }

    public interface OnCrashedListener {
        void onCrashed(String log);
    }

    /**
     * 收集错误信息 发送错误报告
     * 如果用户没有处理则让系统默认的异常处理器来处理
     */
    final UncaughtExceptionHandler errorHandler = (thread, ex) -> {

        // 收集错误信息 发送错误报告
        handleException(ex);

        // 如果用户没有处理则让系统默认的异常处理器来处理
        assert mDefaultHandler != null;
        mDefaultHandler.uncaughtException(thread, ex);
        ThreadUtil.sleep(2000);

        // 退出程序
        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(1);
    };


}
